from typing import List, Optional
from sqlalchemy.orm import Session
from sqlalchemy import or_
from fastapi import HTTPException, status

from app.models.role import Role
from app.models.permission import Permission
from app.models.role_permission import RolePermission
from app.schemas.role import RoleCreate, RoleUpdate


class RoleService:
    """角色服务类"""
    
    def __init__(self, db: Session):
        self.db = db
    
    def get_by_id(self, role_id: int) -> Optional[Role]:
        """根据ID获取角色"""
        return self.db.query(Role).filter(Role.id == role_id).first()
    
    def get_by_name(self, name: str) -> Optional[Role]:
        """根据名称获取角色"""
        return self.db.query(Role).filter(Role.name == name).first()
    
    def get_all(self, skip: int = 0, limit: int = 100, is_active: Optional[bool] = None) -> List[Role]:
        """获取所有角色"""
        query = self.db.query(Role)
        if is_active is not None:
            query = query.filter(Role.is_active == is_active)
        return query.order_by(Role.level.desc(), Role.created_at).offset(skip).limit(limit).all()
    
    def search_roles(self, keyword: str, skip: int = 0, limit: int = 100) -> List[Role]:
        """搜索角色"""
        return self.db.query(Role).filter(
            or_(
                Role.name.contains(keyword),
                Role.display_name.contains(keyword),
                Role.description.contains(keyword)
            )
        ).offset(skip).limit(limit).all()
    
    def create_role(self, role_data: RoleCreate) -> Role:
        """创建角色"""
        # 检查角色名称是否已存在
        if self.get_by_name(role_data.name):
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="角色名称已存在"
            )
        
        db_role = Role(
            name=role_data.name,
            display_name=role_data.display_name,
            description=role_data.description,
            level=role_data.level,
            is_active=role_data.is_active,
            is_system=role_data.is_system
        )
        
        self.db.add(db_role)
        self.db.commit()
        self.db.refresh(db_role)
        
        # 分配权限
        if role_data.permission_ids:
            self.assign_permissions(db_role.id, role_data.permission_ids)
            self.db.refresh(db_role)
        
        return db_role
    
    def update_role(self, role_id: int, role_data: RoleUpdate) -> Role:
        """更新角色"""
        role = self.get_by_id(role_id)
        if not role:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="角色不存在"
            )
        
        # 检查系统角色
        if role.is_system:
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail="系统角色不允许修改"
            )
        
        # 检查角色名称是否被占用
        if role_data.name and role_data.name != role.name:
            existing_role = self.get_by_name(role_data.name)
            if existing_role:
                raise HTTPException(
                    status_code=status.HTTP_400_BAD_REQUEST,
                    detail="角色名称已存在"
                )
        
        # 更新角色字段
        update_data = role_data.dict(exclude_unset=True)
        for field, value in update_data.items():
            if field != "permission_ids":
                setattr(role, field, value)
        
        self.db.commit()
        self.db.refresh(role)
        
        # 更新权限
        if "permission_ids" in update_data:
            self.assign_permissions(role_id, update_data["permission_ids"])
            self.db.refresh(role)
        
        return role
    
    def delete_role(self, role_id: int) -> bool:
        """删除角色"""
        role = self.get_by_id(role_id)
        if not role:
            return False
        
        # 检查系统角色
        if role.is_system:
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail="系统角色不允许删除"
            )
        
        # 检查是否有用户在使用这个角色
        if role.users:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="角色正在被用户使用，无法删除"
            )
        
        self.db.delete(role)
        self.db.commit()
        return True
    
    def assign_permissions(self, role_id: int, permission_ids: List[int]) -> None:
        """分配权限给角色"""
        role = self.get_by_id(role_id)
        if not role:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="角色不存在"
            )
        
        # 移除现有权限关联
        self.db.query(RolePermission).filter(RolePermission.role_id == role_id).delete()
        
        # 添加新的权限关联
        for permission_id in permission_ids:
            permission = self.db.query(Permission).filter(Permission.id == permission_id).first()
            if permission and permission.is_active:
                role_permission = RolePermission(
                    role_id=role_id,
                    permission_id=permission_id,
                    is_active=True
                )
                self.db.add(role_permission)
        
        self.db.commit()
    
    def get_role_permissions(self, role_id: int) -> List[Permission]:
        """获取角色的所有权限"""
        role = self.get_by_id(role_id)
        if not role:
            return []
        return [perm for perm in role.permissions if perm.is_active]
    
    def get_role_permission_names(self, role_id: int) -> List[str]:
        """获取角色的所有权限名称"""
        permissions = self.get_role_permissions(role_id)
        return [perm.name for perm in permissions]
    
    def has_permission(self, role_id: int, permission_name: str) -> bool:
        """检查角色是否有特定权限"""
        role = self.get_by_id(role_id)
        if not role:
            return False
        return role.has_permission(permission_name)
    
    def get_system_roles(self) -> List[Role]:
        """获取所有系统角色"""
        return self.db.query(Role).filter(Role.is_system == True).all()
    
    def get_custom_roles(self) -> List[Role]:
        """获取所有自定义角色"""
        return self.db.query(Role).filter(Role.is_system == False).all()